package com.moshang.exportsql.util;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author xieww
 * @description redis缓存工具类
 * @date 2023/1/30 15:16
 */
@Component
@Slf4j
public class RedisCacheUtils {
    private static RedisTemplate<String, String> template;

    @Autowired
    public RedisCacheUtils(RedisTemplate<String, String> template) {
        RedisCacheUtils.template = template;

    }
    /**
     * 写入缓存
     *
     * @param key
     * @param value
     * @return
     */
    public static boolean set(final String key, Object value) {
        boolean result = false;
        try {
            String jsonStr = JSONUtil.toJsonStr(value);
            ValueOperations<String, String> operations = template.opsForValue();
            operations.set(key, jsonStr);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    /**
     * 写入缓存
     *
     * @param key
     * @param value
     * @return
     */
    public static boolean set(final String key, String value) {
        boolean result = false;
        try {
            ValueOperations<String, String> operations = template.opsForValue();
            operations.set(key, value);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 写入缓存设置时效时间
     *
     * @param key
     * @param value
     * @param expireTime 超时时间,秒
     * @return
     */
    public static boolean set(final String key, String value, long expireTime) {
        boolean result = false;
        try {
            ValueOperations<String, String> operations = template.opsForValue();
            operations.set(key, value,expireTime, TimeUnit.SECONDS);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 写入缓存设置时效时间
     *
     * @param key
     * @param value
     * @return
     */
    public static boolean set(final String key, String value,long timeout, TimeUnit unit) {
        boolean result = false;
        try {
            ValueOperations<String, String> operations = template.opsForValue();
            operations.set(key, value ,timeout, unit);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 批量删除对应的value
     *
     * @param keys
     */
    public static void delete(final String... keys) {
        template.delete(Arrays.asList(keys));
    }


    /**
     * 根据前缀删除
     *
     * @param prefix
     */
    public static void deleteByPrefix(final String prefix) {

        Set<String> keys = template.keys(prefix + "*");
        template.delete(keys);
    }
    /**
     * 根据前缀获取
     *
     * @param prefix
     */
    public static List<String> getByPrefix(final String prefix) {

        Set<String> keys = template.keys(prefix + "*");
        List<String> results = multiGet(keys);
        return results;
    }
    /**
     * 批量删除对应的value
     *
     * @param keys
     */
    public static void delete(final Collection<String> keys) {
        template.delete(keys);
    }

    /**
     * 删除对应的value
     *
     * @param key
     */
    public static void delete(final String key) {
        if (exists(key)) {
            Boolean delete = template.delete(key);
        }
    }

    /**
     * 判断缓存中是否有对应的value
     *
     * @param key
     * @return
     */
    public static boolean exists(final String key) {
        return Boolean.TRUE.equals(template.hasKey(key));
    }

    /**
     * 读取缓存
     *
     * @param key
     * @return
     */
    public static String get(final String key) {
        String result = null;
        ValueOperations<String, String> operations = template.opsForValue();
        result = operations.get(key);
        return result;
    }

    public static Set<String> scan(String pattern) {
        Set<String> keys = new HashSet<>();
        RedisConnection connection = Objects.requireNonNull(template.getConnectionFactory()).getConnection();
        ScanOptions scanOptions = ScanOptions.scanOptions()
                .match(pattern)
                .count(10000)
                .build();
        Cursor<byte[]> cursor = connection.scan(scanOptions);
        while (cursor.hasNext()) {
            keys.add(new String(cursor.next()));
        }
        return keys;
    }

    /**
     * 读取缓存
     *
     * @param key
     * @return
     */
    public static List<String> multiGet(final Collection<String> key) {
        List<String> result;
        ValueOperations<String, String> operations = template.opsForValue();
        result = operations.multiGet(key);
        assert result != null;
        return result.stream()
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }

    /**
     * 读取缓存
     *
     * @param key
     * @return
     */
    public static Map<Object, Object> getMap(final String key) {
        Map<Object, Object> operations = template.opsForHash().entries(key);
        return operations;
    }

    public static void setMap(final String key, final Map<Object, Object> dataMap) {
        if (dataMap != null) {
            template.opsForHash().putAll(key, dataMap);
        }
    }
    /**
     *
     * @author  dongjunqi
     * @date  2021/7/26 6:05 下午
     * @param key: key
     * @param num: 需要增加的数字,正值递增,负值递减
     * @return  java.lang.Long
     **/
    public static Long incr(final String key,Long num){
        return template.boundValueOps(key).increment(num);
    }


    /**
     *
     * @author  dongjunqi
     * @date  2021/7/26 6:05 下午
     * @param key: key
     * @param num: 需要增加的数字,正值递增,负值递减
     * @param timeout 超时时间
     * @return  java.lang.Long
     **/
    public static Long incr(final String key,Long num,long timeout){
        Long increment = template.boundValueOps(key).increment(num);
        template.expire(key,timeout,TimeUnit.SECONDS);
        return increment;
    }
    /**
     * 实现命令：expire 设置过期时间，单位秒
     *
     * @param key
     * @param timeout 超时时间,单位秒
     */
    public static void expire(String key, long timeout) {
        template.expire(key,timeout,TimeUnit.SECONDS);
    }

    /**
     * HashSet
     *
     * @param key 键
     * @param map 对应多个键值
     * @return true 成功 false 失败
     */
    public static  <T> boolean hmset(String key, Map<String, T> map) {
        try {
            if (StrUtil.isNotBlank(key) && Objects.nonNull(map) && !map.isEmpty()) {
                template.opsForHash().putAll(key, map);
                return true;
            }
            return false;
        } catch (Exception e) {
            log.error("hmset error:{}", e.getMessage(), e);
            return false;
        }
    }
    /**
     * 向一张hash表中放入数据,如果不存在将创建
     *
     * @param key       键
     * @param hashKey   hash键
     * @param hashValue hash值
     * @return true 成功 false失败
     */
    public static <T> boolean hset(String key, String hashKey, T hashValue) {
        try {
            if (StrUtil.isNotBlank(key) && StrUtil.isNotBlank(hashKey)) {
                template.opsForHash().put(key, hashKey, hashValue);
                return true;
            }
            return false;
        } catch (Exception e) {
            log.error("hset error:{}", e.getMessage(), e);
            return false;
        }
    }
    /**
     * 向一张hash表中放入数据,如果不存在将创建
     *
     * @param key       键
     * @param hashKey   项
     * @param hashValue 值
     * @param time      时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
     * @return true 成功 false失败
     */
    public static boolean hset(String key, String hashKey, Object hashValue, long time) {
        try {
            if (StrUtil.isNotBlank(key) && StrUtil.isNotBlank(hashKey)) {
                template.opsForHash().put(key, hashKey, hashValue);
                if (time > 0) {
                    expire(key, time);
                }
                return true;
            }
            return false;
        } catch (Exception e) {
            log.error("hset with time error:{}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 删除hash表中的值
     *
     * @param key  键 不能为null
     * @param item 项 可以使多个 不能为null
     */
    public static void hdel(String key, Object... item) {
        template.opsForHash().delete(key, item);
    }
    /**
     * HashGet
     *
     * @param key     键 不能为null
     * @param hashKey 项 不能为null
     * @return 值
     */
    public static <T> T hget(String key, String hashKey) {
        if (StrUtil.isNotBlank(key) && StrUtil.isNotBlank(hashKey)) {
            HashOperations<String, String, T> ops = template.opsForHash();
            return ops.get(key, hashKey);
        }
        return null;
    }

    public static <T> List<T> hgetList(String key, String hashKey, Class<T> clazz) {
        if (StrUtil.isNotBlank(key) && StrUtil.isNotBlank(hashKey)) {
            HashOperations<String, String, List<T>> ops = template.opsForHash();
            List<T> list = ops.get(key, hashKey);
            if (!CollectionUtils.isEmpty(list)) {
                return list.stream().filter(Objects::nonNull).collect(Collectors.toList());
            }
        }
        return Collections.emptyList();
    }

    public static <T> List<T> hmget(String key, Collection<String> hashKeys, Class<T> clazz) {
        if (StrUtil.isNotBlank(key) && !CollectionUtils.isEmpty(hashKeys)) {
            HashOperations<String, String, T> ops = template.opsForHash();
            List<T> list = ops.multiGet(key, hashKeys);
            if (!CollectionUtils.isEmpty(list)) {
                return list.stream().filter(Objects::nonNull).collect(Collectors.toList());
            }
        }
        return Collections.emptyList();
    }

    public static <T> Map<String,T> hmget(String key, Class<T> clazz) {
        if (StrUtil.isNotBlank(key)) {
            HashOperations<String, String, T> hashOps = template.opsForHash();
            return hashOps.entries(key);
        }
        return MapUtil.empty();
    }

    public static <T> List<T> hmgetList(String key, Collection<String> hashKeys, Class<T> clazz) {
        if (StrUtil.isNotBlank(key) && !CollectionUtils.isEmpty(hashKeys)) {
            HashOperations<String, String, List<T>> ops = template.opsForHash();
            List<List<T>> lists = ops.multiGet(key, hashKeys);
            if (CollectionUtils.isEmpty(lists)) {
                return null;
            }
            List<T> resList = new ArrayList<>();
            lists.forEach(l -> {
                if (!CollectionUtils.isEmpty(l)) {
                    resList.addAll(l);
                }
            });
            return resList;
        }
        return Collections.emptyList();
    }
    /**
     * 判断hash表中是否有该项的值
     *
     * @param key  键 不能为null
     * @param item 项 不能为null
     * @return true 存在 false不存在
     */
    public static boolean hHasKey(String key, String item) {
        return template.opsForHash().hasKey(key, item);
    }

}
